﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.UserData;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace LiveEduWizard
{
    public enum AppointmentType
    {
        Subject,
        Homework,
        Project,
        Test
    }

    public class AppointmentViewModel : INotifyPropertyChanged
    {
        public AppointmentViewModel()
        {
            Related = new ObservableCollection<AppointmentViewModel>();
        }

        public AppointmentViewModel(Appointment appointment)
            : this()
        {
            SetType(appointment.Subject);
            SetSubjectAndTitle(appointment.Subject);

            Start = appointment.StartTime;
            end = appointment.EndTime;

            details = appointment.Details == null ? "" : appointment.Details.TrimEnd();

            location = appointment.Location == null ? "" : appointment.Location;

            organizer = appointment.Organizer;

            attendees = new ObservableCollection<Attendee>(appointment.Attendees);
        }

        public static void CreateRelation(AppointmentViewModel first, AppointmentViewModel second)
        {
            first.AddRelated(second);
            second.AddRelated(first);            
        }

        private void AddRelated(AppointmentViewModel appointment)
        {
            Related.Add(appointment);

            switch (appointment.Type)
            {
                case AppointmentType.Homework:
                    HasHomework = true;
                    break;
                case AppointmentType.Project:
                    HasProject = true;
                    break;
                case AppointmentType.Test:
                    HasTest = true;
                    break;
            }
        }

        private void SetType(string subject)
        {
            type = AppointmentType.Subject;

            if (subject != null
                && subject.Length > 4 
                && subject[0] == '['
                && subject[2] == ':'
                && subject.IndexOf(']') > 3)
            {
                switch (subject[1])
                {
                    case 'H':
                        type = AppointmentType.Homework;
                        break;
                    case 'P':
                        type = AppointmentType.Project;
                        break;
                    case 'T':
                        type = AppointmentType.Test;
                        break;
                }
            }
        }

        private void SetSubjectAndTitle(string subject)
        {
            if (subject == null)
            {
                this.subject = "";
                title = "";
            }
            else if (type == AppointmentType.Subject)
            {
                this.subject = "";
                title = subject.Trim();
            }
            else
            {
                int braclet = subject.IndexOf(']');

                this.subject = subject.Substring(3, braclet - 3).Trim();

                if (braclet < subject.Length - 1)
                    this.title = subject.Substring(braclet + 1).Trim();
                else
                    this.title = "";
            }
        }

        public ObservableCollection<AppointmentViewModel> Related { get; private set; }

        private bool hasHomework;
        public bool HasHomework
        {
            get { return hasHomework; }
            set
            {
                if (value != hasHomework)
                {
                    hasHomework = value;
                    NotifyPropertyChanged("HasHomework");
                }
            }
        }

        private bool hasProject;
        public bool HasProject
        {
            get { return hasProject; }
            set
            {
                if (value != hasProject)
                {
                    hasProject = value;
                    NotifyPropertyChanged("HasProject");
                }
            }
        }

        private bool hasTest;
        public bool HasTest
        {
            get { return hasTest; }
            set
            {
                if (value != hasTest)
                {
                    hasTest = value;
                    NotifyPropertyChanged("HasTest");
                }
            }
        }

        private AppointmentType type;
        public AppointmentType Type
        {
            get { return type; }
            set
            {
                if (value != type)
                {
                    type = value;
                    NotifyPropertyChanged("Type");
                }
            }
        }

        private DateTime start;
        public DateTime Start
        {
            get { return start; }
            set
            {
                if (value != start)
                {
                    start = value;

                    if (start.Month > 1 || start.Day > (start.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)start.DayOfWeek))
                        weekYear = start.Year;
                    else //last week in previous year
                        weekYear = start.Year - 1;

                    CalculateWeek();

                    NotifyPropertyChanged("Start");
                    NotifyPropertyChanged("Week");
                    NotifyPropertyChanged("WeekYear");
                    NotifyPropertyChanged("AgendaTime");
                }
            }
        }

        private void CalculateWeek()
        {
            DateTime start;

            if (WeekYear != this.start.Year)
                start = new DateTime(WeekYear, 12, 31); //count week to last day of previous year
            else
                start = this.start;

            DayOfWeek firstDay = new DateTime(start.Year, 1, 1, 12, 0, 0).DayOfWeek;
            week = (start.DayOfYear - (start.DayOfWeek == DayOfWeek.Sunday ? 6 : ((int)start.DayOfWeek - 1))
                + (firstDay == DayOfWeek.Sunday ? 5 : ((int)firstDay - 2))) / 7 + 1;
        }

        private int week;
        public int Week
        {
            get
            {
                return week;
            }
        }

        private int weekYear;
        public int WeekYear
        {
            get
            {
                return weekYear;
            }
        }

        public string AgendaTime
        {
            get
            {
                if (type == AppointmentType.Subject || type == AppointmentType.Test)
                    return string.Format("{0} ({1:0.0}h)", start.ToShortTimeString(), (end - start).TotalHours);
                else
                    return start.ToShortTimeString();
            }
        }

        public string DetailDateTime
        {
            get
            {
                if (type == AppointmentType.Subject || type == AppointmentType.Test)
                {
                    if (start.Date == end.Date)
                        return string.Format("{0:dddd, dd MMMM yyyy}, {1} - {2}", start, start.ToShortTimeString(), end.ToShortTimeString());
                    else
                        return string.Format("{0}, {1} - {2}, {3}", 
                            start.ToShortDateString(), start.ToShortTimeString(), 
                            end.ToShortDateString(), end.ToShortTimeString());
                }
                else
                    return start.ToString("dddd, dd MMMM yyyy, ") + start.ToShortTimeString();
            }
        }

        private DateTime end;
        public DateTime End
        {
            get { return end; }
            set 
            {
                if (value != end)
                {
                    end = value;
                    NotifyPropertyChanged("End");
                }
            }
        }

        private string subject;
        public string Subject
        {
            get
            {
                return subject;
            }
            set
            {
                if (value != subject)
                {
                    subject = value;
                    NotifyPropertyChanged("Subject");
                }
            }
        }

        private string title;
        public string Title
        {
            get
            {
                return title;
            }
            set
            {
                if (value != title)
                {
                    title = value;
                    NotifyPropertyChanged("Title");
                }
            }
        }

        private string details;
        public string Details
        {
            get
            {
                return details;
            }
            set
            {
                if (value != details)
                {
                    details = value;
                    NotifyPropertyChanged("Details");
                }
            }
        }

        private string location;
        public string Location
        {
            get
            {
                return location;
            }
            set
            {
                if (value != location)
                {
                    location = value;
                    NotifyPropertyChanged("Location");
                }
            }
        }

        private Attendee organizer;
        public Attendee Organizer
        {
            get
            {
                return organizer;
            }
            set
            {
                if (value != organizer)
                {
                    organizer = value;
                    NotifyPropertyChanged("Organizer");
                }
            }
        }

        private ObservableCollection<Attendee> attendees;
        public ObservableCollection<Attendee> Attendees
        {
            get
            {
                return attendees;
            }
            set
            {
                if (value != attendees)
                {
                    attendees = value;
                    NotifyPropertyChanged("Attendees");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }        
    }
}